{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3c5dbcc9ae0c"
      },
      "source": [
        "##### Copyright 2025 Google LLC."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "392d7579b19b"
      },
      "outputs": [],
      "source": [
        "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "#\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "#     https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5912063a89d0"
      },
      "source": [
        "# File Search Quickstart\n",
        "\n",
        "<a target=\"_blank\" href=\"https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/File_Search.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" height=30/></a>\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dcdfc6c70698"
      },
      "source": [
        "The [File Search tool](http://ai.google.dev/gemini-api/docs/file-search) allows you to build powerful retrieval-augmented generation (RAG) applications using Gemini. It lets you upload documents to a managed store and then use them as a tool during model generation, enabling Gemini to answer questions based on your specific data with accurate citations.\n",
        "\n",
        "In this quickstart, you will learn how to:\n",
        "\n",
        "*   Create a File Search Store.\n",
        "*   Upload documents to the store.\n",
        "*   Use the store as a tool in `generate_content`.\n",
        "*   Cite the sources used during generation.\n",
        "*   Filter search results using custom metadata.\n",
        "*   Manage your documents and stores.\n",
        "\n",
        "For information on how pricing works for File Search, including details on what is available free of charge, see the [pricing information](https://ai.google.dev/gemini-api/docs/file-search#pricing)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7aa879cbb837"
      },
      "source": [
        "## Install dependencies\n",
        "\n",
        "First, install the Google Gen AI SDK.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0fde3fc7bc55"
      },
      "outputs": [],
      "source": [
        "# SDK 1.49 introduced File Search\n",
        "%pip install -U -q 'google-genai>=1.49.0'"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9m23flVTrczi"
      },
      "source": [
        "### Authentication\n",
        "\n",
        "**Important:** The File Search API uses API keys for authentication and access. Uploaded files are associated with the API key's cloud project. Unlike other Gemini APIs that use API keys, your API key also grants access to all data you've uploaded to file stores, so take extra care in keeping your API key secure. For best practices on securing API keys, refer to Google's [documentation](https://support.google.com/googleapi/answer/6310037)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1595178b4ad1"
      },
      "source": [
        "#### Set up your API key\n",
        "\n",
        "To run the following cell, your API key must be stored in a Colab Secret named `GEMINI_API_KEY`. If you don't already have an API key, or you're not sure how to create a Colab Secret, see [Authentication](./Authentication.ipynb) for an example."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0ec2640756b4"
      },
      "outputs": [],
      "source": [
        "from google import genai\n",
        "from google.colab import userdata\n",
        "from google.genai import types\n",
        "\n",
        "GEMINI_API_KEY = userdata.get(\"GEMINI_API_KEY\")\n",
        "client = genai.Client(api_key=GEMINI_API_KEY)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9b88d710173f"
      },
      "source": [
        "## Basic file search\n",
        "\n",
        "In this section, you will download a sample document, create a File Search Store, and use it to answer questions."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2e8a3ea29906"
      },
      "source": [
        "### Create a File Search Store\n",
        "\n",
        "Create a new File Search Store to hold your documents.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8bee2cb8eab4"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Created store: fileSearchStores/my-file-search-store-9fimh45e9q14\n"
          ]
        }
      ],
      "source": [
        "file_search_store = client.file_search_stores.create(\n",
        "    config=types.CreateFileSearchStoreConfig(\n",
        "        display_name='My File Search Store'\n",
        "    )\n",
        ")\n",
        "\n",
        "print(f\"Created store: {file_search_store.name}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fpPPbbi3saoB"
      },
      "source": [
        "### Download a sample document\n",
        "\n",
        "Download \"A Survey of Modernist Poetry\" from Project Gutenberg as a sample text file."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4fe9d5f99164"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "﻿The Project Gutenberg eBook of A survey of modernist poetry\r\n",
            "    \r\n",
            "This ebook is for the use of anyone anywhere in the United States and\r\n",
            "most other parts of the world at no cost and with almost no restrictions\r\n",
            "whatsoever. You may copy it, give it away or re-use it under the terms\r\n",
            "of the Project Gutenberg License included with this ebook or online\r\n",
            "at www.gutenberg.org. If you are not located in the United States,\r\n",
            "you will have to check the laws of the country where you are located\r\n",
            "before using this eBook.\r\n",
            "\r\n"
          ]
        }
      ],
      "source": [
        "!wget -q https://www.gutenberg.org/cache/epub/76401/pg76401.txt -O sample_poetry.txt\n",
        "!head sample_poetry.txt"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ac909a0e287a"
      },
      "source": [
        "### Upload a file to the store\n",
        "\n",
        "Upload the text file directly to the store. The ingestion process includes some processing, so you need to wait for it to complete before you can search."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "85735b956b8a"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Upload started: fileSearchStores/my-file-search-store-9fimh45e9q14/upload/operations/a-survey-of-modernist-poetr-rd7al7895r59\n",
            "...\n",
            "Processing complete.\n"
          ]
        }
      ],
      "source": [
        "import time\n",
        "\n",
        "upload_op = client.file_search_stores.upload_to_file_search_store(\n",
        "    file_search_store_name=file_search_store.name,\n",
        "    file='sample_poetry.txt',\n",
        "    config=types.UploadToFileSearchStoreConfig(\n",
        "        display_name='A Survey of Modernist Poetry',\n",
        "    )\n",
        ")\n",
        "\n",
        "print(f\"Upload started: {upload_op.name}\")\n",
        "\n",
        "\n",
        "while not (upload_op := client.operations.get(upload_op)).done:\n",
        "    time.sleep(1)\n",
        "    print(\".\", end=\"\")\n",
        "\n",
        "print()\n",
        "print(\"Processing complete.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oWLBtPUjtuKM"
      },
      "source": [
        "### Alternative: Import from the File API\n",
        "\n",
        "If you have already uploaded documents to the [File API](https://ai.google.dev/gemini-api/docs/files), you can import them directly into a File Store. This may be helpful if a user has performed some interaction with a file already, such as generating a summary, and has approved the file for use in a store."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HwL-2-qsuJml"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Uploaded via File API: files/li0pn1it912i\n",
            "File import started: fileSearchStores/my-file-search-store-9fimh45e9q14/operations/li0pn1it912i-ucqsutd9emb1\n",
            "....\n",
            "Processing complete.\n"
          ]
        }
      ],
      "source": [
        "file_ref = client.files.upload(\n",
        "    file='sample_poetry.txt',\n",
        "    config=types.UploadFileConfig(\n",
        "        display_name='A Survey of Modernist Poetry',\n",
        "        mime_type='text/plain',\n",
        "    )\n",
        ")\n",
        "print(f\"Uploaded via File API: {file_ref.name}\")\n",
        "\n",
        "import_op = client.file_search_stores.import_file(\n",
        "    file_search_store_name=file_search_store.name,\n",
        "    file_name=file_ref.name,\n",
        ")\n",
        "\n",
        "print(f\"File import started: {import_op.name}\")\n",
        "\n",
        "while not (import_op := client.operations.get(import_op)).done:\n",
        "    time.sleep(1)\n",
        "    print(\".\", end=\"\")\n",
        "\n",
        "print()\n",
        "print(\"Processing complete.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "524d3f596933"
      },
      "source": [
        "### Generate content with File Search\n",
        "\n",
        "Now, use the `file_search` tool in a `generate_content` request. Gemini will use the uploaded document to answer your question.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eeb0763ca0d8"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The text discusses E.E. Cummings as a significant poet whose work demands a \"more vigorous imaginative effort\" from the reader than what is typically applied to poetry. His innovations are considered to have a real place in the normal course of poetry-writing, and his acceptance is suggested, if not for his own sake, then for his potential effect on the future reading of poetry of any age or style.\n",
            "\n",
            "One of Cummings' earlier and simpler poems is chosen for analysis in the text, despite its potential to elicit hostility similar to his later work. This particular poem is noted for its suitability for analysis, as it addresses a subject matter that the \"plain reader\" often seeks in poetry. It also appears in Mr. Louis Untermeyer's \"Anthology of Modern American Poetry\" alongside poets who are more willing to cater to the plain reader's intelligence level.\n",
            "\n",
            "The text further suggests that Cummings writes according to a carefully constructed poetic system, but he refrains from providing a critical key to his poems, except as a \"semi-prefatorial confidence.\" This implies that as poems become more independent, the need or sense for a technical guide diminishes. The increasing difficulty of poems would not necessarily hinder understanding but rather make the reader less separated from poetry by technique.\n",
            "\n",
            "Regarding his use of punctuation, the text describes punctuation marks in Cummings' poetry as \"bolts and axels\" that make the poem a \"methodic and fool-proof piece of machinery\" that requires common sense rather than imagination for its operation. The strong reaction against his typography highlights the difficulty in engaging a reader's common sense as much as their imagination.\n",
            "\n",
            "The text concludes by suggesting that while future poems might not all be written \"in the Cummings way,\" his poetry is important as a \"sign of local irritation in the poetic body\" rather than a model for a new tradition. It emphasizes the need to highlight the differences between good and bad poems to the reading public, especially during a time of popular but superficial education.\n"
          ]
        }
      ],
      "source": [
        "MODEL_ID = \"gemini-2.5-flash\" # @param [\"gemini-2.5-flash-lite\", \"gemini-2.5-flash\", \"gemini-2.5-pro\"] {\"allow-input\":true, isTemplate: true}\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents='What does the text say about E.E. Cummings?',\n",
        "    config=types.GenerateContentConfig(\n",
        "        tools=[types.Tool(\n",
        "            file_search=types.FileSearch(\n",
        "                file_search_store_names=[file_search_store.name]\n",
        "            )\n",
        "        )]\n",
        "    )\n",
        ")\n",
        "\n",
        "print(response.text)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3f902af60658"
      },
      "source": [
        "### Inspect grounding metadata\n",
        "\n",
        "The response includes `grounding_metadata` which contains citations and references to the source document. The document chunks used in the generation context are available in `grounding_metadata.grounding_chunks`, and look like this.\n",
        "\n",
        "```python\n",
        "[\n",
        "  GroundingChunk(\n",
        "    retrieved_context=GroundingChunkRetrievedContext(\n",
        "      text=\"\"\"(the snippet of text contained in this chunk)\"\"\",\n",
        "      title='(the title of the document)'\n",
        "    )\n",
        "  ), ...\n",
        "]\n",
        "```"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "08f2fa20812e"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Found 5 grounding chunks.\n",
            "\n",
            "Chunk 1 source: A Survey of Modernist Poetry\n",
            "Chunk text:\n",
            "  alterations in his critical\r\n",
            "  attitude. In the first place, he must admit that what is called our\r\n",
            "  common intelligence is the mind in its least active ...\n",
            "\n",
            "Chunk 2 source: A Survey of Modernist Poetry\n",
            "Chunk text:\n",
            "  unusually suitable for analysis,\r\n",
            "  because it is on just the kind of subject that the plain reader\r\n",
            "  looks for in poetry. It appears, moreover, in Mr. L...\n",
            "\n",
            "Chunk 3 source: A Survey of Modernist Poetry\n",
            "Chunk text:\n",
            "  4th of July the eyes of mice and Niagara\r\n",
            "   Falls) that my “poems” are competing. They are also competing with\r\n",
            "   each other, with elephants and with El...\n",
            "\n",
            "Chunk 4 source: A Survey of Modernist Poetry\n",
            "Chunk text:\n",
            "  Mr. Cummings or for any poet to stabilize a poem once and\r\n",
            "  for all. Punctuation marks in Mr. Cummings’ poetry are the bolts and\r\n",
            "  axels that make the p...\n",
            "\n",
            "Chunk 5 source: A Survey of Modernist Poetry\n",
            "Chunk text:\n",
            "  and to\r\n",
            "  put _dream_ in its more logical position, since in the original\r\n",
            "  poem it is doing double duty for a specific image (_fishing-net_,\r\n",
            "  following ...\n"
          ]
        }
      ],
      "source": [
        "import textwrap\n",
        "\n",
        "grounding = response.candidates[0].grounding_metadata\n",
        "\n",
        "if grounding and grounding.grounding_chunks:\n",
        "    print(f\"Found {len(grounding.grounding_chunks)} grounding chunks.\")\n",
        "    for i, chunk in enumerate(grounding.grounding_chunks, start=1):\n",
        "        print(f\"\\nChunk {i} source: {chunk.retrieved_context.title}\")\n",
        "        print(\"Chunk text:\")\n",
        "        print(textwrap.indent(chunk.retrieved_context.text[:150] + \"...\", \"  \"))\n",
        "else:\n",
        "    print(\"No grounding metadata found.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "x-fRNVg7w7jv"
      },
      "source": [
        "Additionally, `grounding_metadata` includes `grounding_supports` that provide references from the response text to the supporting documents, and can be used for providing annotations.\n",
        "\n",
        "The supports look like this.\n",
        "\n",
        "```python\n",
        "[\n",
        "  GroundingSupport(\n",
        "    grounding_chunk_indices=[\n",
        "      0,  # The index in `grounding_chunks` to which this corresponds\n",
        "    ],\n",
        "    segment=Segment(\n",
        "      start_index=123,  # Indices into the generated text\n",
        "      end_index=456,\n",
        "      text='(the span of generated text being supported)'\n",
        "    )\n",
        "  ), ...\n",
        "]\n",
        "```"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ajvn48a_1qyw"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": "The text discusses E.E. Cummings as a significant poet whose work demands a \"more vigorous imaginative effort\" from the reader than what is typically applied to poetry. **His innovations are considered to have a real place in the normal course of poetry-writing, and his acceptance is suggested, if not for his own sake, then for his potential effect on the future reading of poetry of any age or style**<sup>0</sup>.\n\nOne of Cummings' earlier and simpler poems is chosen for analysis in the text, despite its potential to elicit hostility similar to his later work. This particular poem is noted for its suitability for analysis, as it addresses a subject matter that the \"plain reader\" often seeks in poetry. It also appears in Mr. **Louis Untermeyer's \"Anthology of Modern American Poetry\" alongside poets who are more willing to cater to the plain reader's intelligence level**<sup>0, 1</sup>.\n\nThe text further suggests that Cummings writes according to a carefully constructed poetic system, but he refrains from providing a critical key to his poems, except as a \"semi-prefatorial confidence.\" This implies that as poems become more independent, the need or sense for a technical guide diminishes. **The increasing difficulty of poems would not necessarily hinder understanding but rather make the reader less separated from poetry by technique**<sup>2</sup>.\n\nRegarding his use of punctuation, the text describes punctuation marks in Cummings' poetry as \"bolts and axels\" that make the poem a \"methodic and fool-proof piece of machinery\" that requires common sense rather than imagination for its operation. **The strong reaction against his typography highlights the difficulty in engaging a reader's common sense as much as their imagination**<sup>3</sup>.\n\nThe text concludes by suggesting that while future poems might not all be written \"in the Cummings way,\" his poetry is important as a \"sign of local irritation in the poetic body\" rather than a model for a new tradition. **It emphasizes the need to highlight the differences between good and bad poems to the reading public, especially during a time of popular but superficial education**<sup>4</sup>.",
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from IPython.display import Markdown, display\n",
        "\n",
        "# Accumulate the response as it is annotated.\n",
        "annotated_response_parts = []\n",
        "\n",
        "if not grounding or not grounding.grounding_supports:\n",
        "    print(\"No grounding metadata or supports found for annotation.\")\n",
        "else:\n",
        "    cursor = 0\n",
        "    for support in grounding.grounding_supports:\n",
        "        # Add the text before the current support\n",
        "        annotated_response_parts.append(response.text[cursor:support.segment.start_index])\n",
        "\n",
        "        # Construct the superscript citation from chunk IDs\n",
        "        chunk_ids = ', '.join(map(str, support.grounding_chunk_indices))\n",
        "        citation = f\"<sup>{chunk_ids}</sup>\"\n",
        "\n",
        "        # Append the formatted, cited, supported text\n",
        "        annotated_response_parts.append(f\"**{support.segment.text}**{citation}\")\n",
        "\n",
        "        cursor = support.segment.end_index\n",
        "\n",
        "    # Append any remaining text after the last support\n",
        "    annotated_response_parts.append(response.text[cursor:])\n",
        "\n",
        "    final_annotated_response = \"\".join(annotated_response_parts)\n",
        "    display(Markdown(final_annotated_response))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "db7462b4a373"
      },
      "source": [
        "## Metadata Filtering\n",
        "\n",
        "While adding documents, you can attach custom metadata to your files and use it to filter search results.\n",
        "\n",
        "### Upload a file with metadata\n",
        "\n",
        "Download another book, \"Alice's Adventures in Wonderland\", and upload it with information about genre and author."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "766acc8a2668"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "*** START OF THE PROJECT GUTENBERG EBOOK 11 ***\n",
            "\n",
            "[Illustration]\n",
            "\n",
            "\n",
            "\n",
            "\n",
            "Alice’s Adventures in Wonderland\n",
            "\n",
            "by Lewis Carroll\n"
          ]
        }
      ],
      "source": [
        "!wget -q https://www.gutenberg.org/files/11/11-0.txt -O alice_in_wonderland.txt\n",
        "!head alice_in_wonderland.txt"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "426d61c0f34e"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "..\n",
            "Upload complete.\n"
          ]
        }
      ],
      "source": [
        "upload_op = client.file_search_stores.upload_to_file_search_store(\n",
        "    file_search_store_name=file_search_store.name,\n",
        "    file='alice_in_wonderland.txt',\n",
        "    config=types.UploadToFileSearchStoreConfig(\n",
        "        display_name='Alice in Wonderland',\n",
        "        custom_metadata=[\n",
        "            types.CustomMetadata(key='genre', string_value='fiction'),\n",
        "            types.CustomMetadata(key='author', string_value='Lewis Carroll'),\n",
        "        ]\n",
        "    )\n",
        ")\n",
        "\n",
        "while not (upload_op := client.operations.get(upload_op)).done:\n",
        "    time.sleep(1)\n",
        "    print(\".\", end=\"\")\n",
        "\n",
        "print()\n",
        "print(\"Upload complete.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wQibG8g46XFm"
      },
      "source": [
        "Custom metadata can be provided as `string_value`, `numeric_value` or `string_list_value` types."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7WiiXjov6iWH"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'numeric_value', 'string_list_value', 'string_value'}"
            ]
          },
          "execution_count": 82,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "types.CustomMetadata.model_fields.keys() - {'key'}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4da204c2e320"
      },
      "source": [
        "### Query with metadata filter\n",
        "\n",
        "Now, ask a question that could apply to either book, but use a filter to restrict it to just one. For example, ask about a \"Queen\" but filter for 'fiction'.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "b8989b1f142c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Based on the information available, \"the Queen\" refers to the Queen of Hearts from Lewis Carroll's *Alice in Wonderland*. She is depicted as a tyrannical ruler who frequently shouts \"Off with his head!\" or \"Off with her head!\". She is known for her severe demeanor and short temper. For instance, she becomes crimson with fury when Alice responds surprisingly to her questions. The Queen is part of a grand procession alongside the King of Hearts, with soldiers and courtiers accompanying them. She is often seen playing croquet and sentencing players to execution.\n",
            "--------------------------------------------------------------------------------\n",
            "5 sources used from Alice in Wonderland\n"
          ]
        }
      ],
      "source": [
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents='Who is the Queen?',\n",
        "    config=types.GenerateContentConfig(\n",
        "        tools=[types.Tool(\n",
        "            file_search=types.FileSearch(\n",
        "                file_search_store_names=[file_search_store.name],\n",
        "                metadata_filter='genre = \"fiction\"'\n",
        "            )\n",
        "        )]\n",
        "    )\n",
        ")\n",
        "\n",
        "print(response.text)\n",
        "print('-' * 80)\n",
        "\n",
        "if grounding := response.candidates[0].grounding_metadata:\n",
        "  unique_titles = {c.retrieved_context.title for c in grounding.grounding_chunks}\n",
        "  print(len(grounding.grounding_chunks), \"sources used from\", *unique_titles)\n",
        "else:\n",
        "  print(\"No sources used.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7DcPAv7s8vr9"
      },
      "source": [
        "To learn more about how to build complex filters, read the [AIP-160](https://google.aip.dev/160) spec."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f01e8cb92b4d"
      },
      "source": [
        "## Managing Documents\n",
        "\n",
        "You can also manage individual documents within a store.\n",
        "\n",
        "### List documents\n",
        "\n",
        "List all documents currently in the store.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2c13522dec70"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Documents in fileSearchStores/my-file-search-store-9fimh45e9q14:\n",
            "- A Survey of Modernist Poetry (fileSearchStores/my-file-search-store-9fimh45e9q14/documents/a-survey-of-modernist-poetr-rd7al7895r59)\n",
            "- li0pn1it912i (fileSearchStores/my-file-search-store-9fimh45e9q14/documents/li0pn1it912i-ucqsutd9emb1)\n"
          ]
        }
      ],
      "source": [
        "print(f\"Documents in {file_search_store.name}:\")\n",
        "\n",
        "for doc in client.file_search_stores.documents.list(parent=file_search_store.name):\n",
        "    print(f\"- {doc.display_name} ({doc.name})\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a8fd93bfca73"
      },
      "source": [
        "### Get a document\n",
        "\n",
        "Retrieve details for a specific document, such as its processing status or metadata.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bb0bc85c7ead"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Document details for li0pn1it912i:\n",
            "  Name: fileSearchStores/my-file-search-store-9fimh45e9q14/documents/li0pn1it912i-ucqsutd9emb1\n",
            "  Custom Metadata: None\n"
          ]
        }
      ],
      "source": [
        "# Get a document by ID\n",
        "doc_id = doc.name  # Or set a specific ID here.\n",
        "sample_doc = client.file_search_stores.documents.get(name=doc_id)\n",
        "\n",
        "if sample_doc:\n",
        "    print(f\"Document details for {sample_doc.display_name}:\")\n",
        "    print(f\"  Name: {sample_doc.name}\")\n",
        "    print(f\"  Custom Metadata: {sample_doc.custom_metadata}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "17c8203be887"
      },
      "source": [
        "### Delete a document\n",
        "\n",
        "Remove a specific document from the store without deleting the entire store.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8c668e88095c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Deleted document: fileSearchStores/my-file-search-store-9fimh45e9q14/documents/li0pn1it912i-ucqsutd9emb1\n",
            "\n",
            "Remaining documents:\n",
            "- A Survey of Modernist Poetry\n"
          ]
        }
      ],
      "source": [
        "# Delete a specific document.\n",
        "doc_to_be_deleted = doc_id\n",
        "\n",
        "client.file_search_stores.documents.delete(\n",
        "    name=doc_to_be_deleted,\n",
        "    config=types.DeleteDocumentConfig(\n",
        "        # Set force to delete a non-empty document.\n",
        "        force=True\n",
        "    )\n",
        ")\n",
        "print(f\"Deleted document: {doc_to_be_deleted}\")\n",
        "\n",
        "# Verify deletion\n",
        "print(\"\\nRemaining documents:\")\n",
        "for doc in client.file_search_stores.documents.list(parent=file_search_store.name):\n",
        "    print(f\"- {doc.display_name}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1588036898e8"
      },
      "source": [
        "## Managing File Search Stores\n",
        "\n",
        "You can list, get, and delete your File Search Stores.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8d32cff41a52"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Listing stores:\n",
            "- fileSearchStores/my-file-search-store-9fimh45e9q14 (My File Search Store)\n"
          ]
        }
      ],
      "source": [
        "print(\"Stores:\")\n",
        "\n",
        "for store in client.file_search_stores.list():\n",
        "    print(f\"- {store.name} ({store.display_name})\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "878f4a4ccb2d"
      },
      "source": [
        "## Cleanup\n",
        "\n",
        "It's good practice to delete File Search Stores when you are done with them to avoid unnecessary storage costs.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2ab49e92b349"
      },
      "outputs": [],
      "source": [
        "client.file_search_stores.delete(name=file_search_store.name, config=types.DeleteFileSearchStoreConfig(force=True))\n",
        "print(f\"Deleted store: {file_search_store.name}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "757414455de5"
      },
      "source": [
        "## What's next\n",
        "\n",
        "For more information on the File Search tool, be sure to check these out.\n",
        " * The [File Search guide](https://ai.google.dev/gemini-api/docs/file-search)\n",
        " * [Pricing information](https://ai.google.dev/gemini-api/docs/file-search#pricing)\n",
        " * The detailed [API reference](https://ai.google.dev/api/file-search)\n",
        " * The [File API cookbook](./File_API.ipynb)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "File_Search.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
